#include "bits.h"


//-----------------------------------------------------FONCTIONS---------------------------------------------

//Renvoie le bit n°i d'un char. La position 0 correspond au bit de poids fort (celui de gauche)
int bit(char a, int i)
{
  return (a>>(7-i)) & 1;
}

//Renvoie le bit n°i d'un uint. La position 0 correspond au bit de poids fort (celui de gauche)
int ubit(uint a, int i)
{
  return (a>>(31-i)) & 1;
}

//Renvoie le bit n°i de a,qui est une suite de 0 et de 1 stockée dans un tableau de nb uints
int Nbit(uint* a, int nb, int i)
{
  if (i >= 32 * nb) printf("Erreur : il n'y a que %d bits dans ce nombre et vous demandez le n° %d (fonction Nbit)\n", 32 * nb, i);
  
  return ubit(a[i/32], i%32);
}

//Affiche tous les bits d'un char
void affiche(char a)
{
  int i;
  for (i = 0; i < 8; i++) printf("%d", (a>>(7-i)) & 1);
}

//Affiche tous les bits d'un uint
void uaffiche(uint a)
{
  int i;
  for (i = 0; i < 32; i++) printf("%d", (a>>(31-i)) & 1);
}

//Affiche les N premiers bits de a, qui est une suite de 0 et de 1 stockée dans un tableau de nb uints
void Naffiche(uint* a, int nb, int N)
{
  int i;
  if (N > 32 * nb) printf("Erreur : il n'y a que %d bits dans ce nombre et vous en demandez %d (fonction Naffiche)\n", 32 * nb, N);
  
  for (i = 0; i < N; i++) 
	printf("%d", Nbit(a, nb, i));  
}

//Met à 0 le bit n°i d'un char 
void zero(char* a, int i)
{
  *a &= ~(1<<(7-i));  
}  

//Met à 0 le bit n°i d'un uint 
void uzero(uint* a, int i)
{
  *a &= ~(1<<(31-i));  
}  

//Met à 1 le bit n°i d'un char 
void un(char* a, int i)
{
  *a |= (1<<(7-i));  
}

//Met à 1 le bit n°i d'un uint 
void uun(uint* a, int i)
{
  *a |= (1<<(31-i));  
}

//Met à val (0 ou 1) le bit n°i de a, qui est une suite de 0 et de 1 stockée dans un tableau de nb uints 
void setBit(uint* a, int nb, int i, int val)
{
  if (i > 32 * nb) printf("Erreur : il n'y a que %d bits dans ce nombre et vous demandez le n° %d (fonction setBit)\n", 32 * nb, i);  
				 
  if (val == 0) uzero(&a[i/32], i%32);
  else uun(&a[i/32], i%32);
}

//str est une chaine de 8 caractères (des 0 et des 1). Les bits du char à l'adresse a sont remplacés par les valeurs de str
void edit(char* a, char* str)
{
  int i;
  for (i = 0; i < 8; i++)
  {
    if (str[i] == '0') zero(a, i);
    else un(a, i);
  }
}
    
/*str est une chaine de 32 caractères (des 0 et des 1). Les premiers bits du uint à l'adresse a sont remplacés
 * par les valeurs de str. Les suivants sont mis à 0
 */
void uedit(uint* a, char* str)
{
  int i;
  for (i = 0; i < strlen(str); i++)
  {
    *a = 0;
    if (str[i] == '0') uzero(a, i);
    else uun(a, i);
  }
}

/*a est un tableau de nb uints. Les bits de ce tableau prennent les valeurs de str*/
void Nedit(uint* a, int nb, char* str)
{
  int L = strlen(str);  
  if (L > 32 * nb) printf("Erreur : il n'y a que %d bits dans ce nombre et vous demandez le n° %d (fonction Nedit)\n", 32 * nb, L);
  
  int i;
  for (i = 0; i < nb; i++) a[i] = 0;  
  for (i = 0; i < L; i++) setBit(a, nb, i, (int)(str[i] - '0'));
}

/*Crée un tableau de uints à l'adresse a pour stocker les bits des caractères de la chaîne str
 * et renvoie la taille de ce tableau. Les derniers bits du dernier uint du tableau sont mis à 0.
 */
int Nstore(uint* a, char* str)
{
  int i;
  int L = strlen(str);
  int nb = L / 4; //Un uint occupe 4 octets
  if (L % 4 != 0) nb++;
  
  a = malloc(nb * sizeof(uint));
  
  for (i = 0; i < L * 8; i++) setBit(a, nb, i, bit(str[i/8], i%8) );  
  for (i = L * 8; i < 32 * nb; i++) setBit(a, nb, i, 0);  
  return nb;
}

/*Crée un tableau de uints à l'adresse a pour stocker sous forme de bits le contenu du fichier binaire f
 * et renvoie la taille de ce tableau. Les derniers bits du dernier uint du tableau sont mis à 0.
 */
int NfileStore(uint* a, FILE* f)
{
  int longueurFichier, i;
  fseek(f, 0, SEEK_END);
  longueurFichier = ftell(f); //La longueur est donnée en octets
  int nb = longueurFichier / 4; //Un uint occupe 4 octets
  if (longueurFichier % 4 != 0) nb++;
  
  printf("Il faut %d uint(s) pour stocker les %d octets de ce fichier.\n", nb, longueurFichier);
  a = malloc(nb * sizeof(uint));
  
  char* textF = malloc(longueurFichier * sizeof(char)); //Les caractères du fichier
  fread(textF, sizeof(char), longueurFichier, f);  
  printf("Contenu du fichier crypté : %s\n", textF);  
  
  Nstore(a, textF); //On copie les bits de textF (tableau de caractères) dans a (tableau de uints)  
  //Si la dernière case du tableau a n'est pas pleine, on la complète avec des 0
  for (i = longueurFichier * 8; i < nb * 32; i++) setBit(a, nb, i, 0);   
  return nb;
}

//Renvoie le XOR des bits d'un uint (entre eux)
int uXOR(uint a)
{
  int i;
  int S = 0;
  for (i = 0; i < 32; i++)
  {
    S ^= bit(a,i);
  }
  return S;
}

uint retourne(uint a, int n)
/* Renvoie, dans l'ordre inverse, les n premiers bits de a, avec n <= 32
 * 
 * ex : a = 00010011100110000000000000000000
 *      n = 15
 * 
 * 	La fonction renvoie : 001100111001000 suivi de (32-15) zeros
 */
{
  int i;
  uint b = 0;
  
  if (n > 32)
  {
    printf("Erreur ! n = %d mais on ne peut pas retourner plus de 32 bits.\n", n);
    exit(1);
  }  
  
  for (i = 0; i < n; i++)
  {
    if (ubit(a, n-1-i) == 0) uzero(&b, i);
    else uun(&b, i);    
  }
  
  return b;
}


uint* Nretourne(uint* a, int nb, int n)
// Renvoie, dans l'ordre inverse, les n premiers bits du tableau a 
{
    uint* b = malloc(nb * sizeof(uint));
    
    int i;
    for (i = 0; i < n; i++) setBit(b, nb, i, Nbit(a, nb, n-1-i));
    for (i = n; i < 32 * nb; i++) setBit(b, nb, i, 0);
    
    return b;
}  



void Ndroite(uint* a, int nb)
/*Décale d'un cran vers la droite tous les bits de a, qui est une suite
 * de 0 et de 1 stockée dans un tableau de nb uints
 */
{
  int i;
  
  for (i = nb-1; i > 0; i--)
  {
    a[i] = a[i] >> 1;
    
    if (ubit(a[i-1], 31) == 0) uzero(&a[i], 0);
    else uun(&a[i], 0);
  }
  
  a[0] = a[0] >> 1;
}







